home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1990 / 11 / knowles.asc < prev    next >
Text File  |  1990-10-12  |  44KB  |  1,272 lines

  1. _WINDOWS 3.0 APPLICATION DEVELOPMENT_
  2. by Walter Knowles
  3.  
  4. [LISTING ONE]
  5.  
  6. /******************************************************** 
  7.  * FILE: chekmate.ddl 
  8.  * DESCRIPTION: db_Vista database definition language schema
  9.  *********************************************************/
  10.  
  11. database chekmate {      
  12. /* File definition section */
  13.     data file checks1 = "chekmate.d01" contains system, payor, payee,
  14.                                                 tranPayee, account;
  15.     data file checks2 = "chekmate.d02" contains transaction, actual;
  16.     data file checks3 = "chekmate.d03" contains budget, distribution;
  17.  
  18.     key file checkKey = "chekmate.k01" contains strPayorName, strAccountName,
  19.                                                 strAccountCode, strPayeeCode,
  20.                                                 strPayeeName;
  21.  /* Ewcord definition section   */
  22.     record  payor {
  23.         unique key  char    strPayorName   [35];
  24.                     char    strPayorAddr1  [35];/* single element fields */
  25.                     char    strPayorAddr2  [35];/* are easier in toolbook */
  26.                     char    strPayorCity   [20];
  27.                     char    strPayorState  [3];
  28.                     char    strPayorZip    [10];
  29.                     char    strPayorCtry   [10];
  30.                     char    strPayorTel    [15];
  31.                     char    cPayorRegAdd;   /* values are (a)D(d) and */
  32.                     char    cPayorAccAdd;  /*(a)S(k) on exception processing */
  33.                     char    cPayorPayeeAdd;
  34.                     char    cPayorAccess;  /* values are C(ode) and N(ame) */
  35.                     int     nPayorYear;
  36.                     db_addr dbaPayorCurrBank; 
  37.                     int     nPayorNextRecur;
  38.     }
  39.  
  40.     /*  Account covers both balance sheet and income statement accounts. */
  41.     record  account {
  42.                key  char strAccountName   [35];
  43.                key  char strAccountCode   [15];
  44.                     char strAccountNumber [15];
  45.                     char cAccountType;          /* A L E I E */
  46.                     int  bAccountTax;           /* T= tax related */
  47.                     int  bAccountIsRegister;
  48.     }
  49.     /*  Payee */
  50.     record  payee       {
  51.                key  char    strPayeeName  [35];
  52.                key  char    strPayeeCode  [15];           
  53.                     char    strPayeeAddr1 [35];
  54.                     char    strPayeeAddr2 [35];
  55.                     char    strPayeeCity  [20];
  56.                     char    strPayeeState [3];
  57.                     char    strPayeeZip   [10];
  58.                     char    strPayeeCtry  [10];
  59.                     char    strPayeeTel   [15];
  60.                     /* default account is a set */
  61.                     char    strPayeeMemo  [35];
  62.                     char    strPayeeType  [10];
  63.     }
  64.     /*  Budget records are owned by the account. */
  65.     record  budget {
  66.                     int     nBudgetMonth;       /* number from 1 to 12 */
  67.                     long    lBudgetAmount;      
  68.     }
  69.     /*  Actuals are maintained in order; speeds process of updating register.*/
  70.     record  actual {
  71.                     int     nActualMonth;
  72.                     long    lActualAmount;
  73.     }
  74.     /*  Transactions are headers for distributions. */
  75.     record  transaction {
  76.                     char    cTranType;          /* check, deposit, etc */
  77.                     char    strTranMemo [35];
  78.                     int     bTranClear;         /* T = cleared */
  79.                     int     nTranNumber;        /* Check number */
  80.                     long    lTranDate;          /* Transaction date as a 
  81.                                                    "COBOL" date: ccyymmdd   */
  82.                     long    lTranAmount;
  83.     }
  84.     /*  Distributions are the balancing entries for transactions. */
  85.     record  distribution {
  86.                     long    lDistrAmount;
  87.     }
  88.     /* Set definition section -- Sets with system as parent */
  89.     set system_payor    {
  90.             order   ascending;
  91.             owner   system;
  92.             member  payor by strPayorName;
  93.     }
  94.     set system_payeecode    {
  95.             order   ascending;
  96.             owner   system;
  97.             member  payee by strPayeeCode;
  98.     }
  99.     set system_payeename    {
  100.             order   ascending;
  101.             owner   system;
  102.             member  payee by strPayeeName;
  103.     }
  104.     set system_lastData {
  105.             order   next;
  106.             owner   system;
  107.             member  lastData;
  108.     }
  109.     /* Sets with payor as parent    */
  110.     set payor_accountcode   {
  111.             order   ascending;
  112.             owner   payor;
  113.             member  account by strAccountCode;
  114.     }
  115.     set payor_accounttypecode   {
  116.             order   ascending;
  117.             owner   payor;
  118.             member  account by cAccountType, strAccountCode;
  119.     }
  120.     set payor_accountname   {
  121.             order   ascending;
  122.             owner   payor;
  123.             member  account by strAccountName;
  124.     }
  125.     /* Sets with account as parent */
  126.     set account_budget {
  127.             order   ascending;
  128.             owner   account;
  129.             member  budget      by nBudgetMonth;
  130.     }
  131.     set account_actual {
  132.             order   ascending;
  133.             owner   account;
  134.             member  actual      by nActualMonth;
  135.     }
  136.     set account_distribution {
  137.             order   next;
  138.             owner   account;
  139.             member  distribution;
  140.     }
  141.     /*  account_payee implements default distribution account for payees. */
  142.     set account_payee   {      
  143.             order   next;
  144.             owner   account;
  145.             member  payee;
  146.     }
  147.     /*  sets with payee as owner */
  148.     set payee_transaction   {
  149.             order   next;
  150.             owner   payee;
  151.             member  transaction;
  152.     }
  153.     /*  sets with actual as owner. */
  154.     set actual_transaction_date  {
  155.             order   ascending;
  156.             owner   actual;
  157.             member  transaction     by lTranDate;
  158.     }
  159.     set actual_transaction_number   {
  160.             order   ascending;
  161.             owner   actual;
  162.             member  transaction     by nTranNumber;
  163.     }
  164.     set actual_transaction_type {
  165.             order   ascending;
  166.             owner   actual;
  167.             member  transaction     by cTranType, lTranDate;
  168.     }
  169.     set actual_distribution {
  170.             order   next;
  171.             owner   actual;
  172.             member  distribution;
  173.     }
  174.     /*  sets with transaction as owner  */
  175.     set transaction_distribution    {
  176.             order   next;
  177.             owner   transaction;
  178.             member  distribution;
  179.     }
  180.     set transaction_tranPayee   {
  181.             order   next;
  182.             owner   transaction;
  183.             member  tranPayee;
  184.     }
  185.     
  186. }
  187.  
  188.  
  189. [LISTING TWO]
  190.  
  191. to handle LINKDLLS
  192.  
  193.     -- use the Windows kernel for memory management
  194.     linkdll "kernel.exe"
  195.         word globalAlloc (word,dword)
  196.         word globalFree (word)
  197.         pointer globalLock (word)
  198.         word globalReAlloc(word,dword,word)
  199.         dword globalSize(word)
  200.         word globalUnlock(word)
  201.     end 
  202.         
  203.     --use ToolBook's file dll for file system access
  204.     linkdll "tbkfile.dll"
  205.         string getCurrentDirectory(string)
  206.         string getCurrentDrive()
  207.     end
  208.  
  209.     -- use Raima's db_VISTA dll for database functionality
  210.     linkdll "vista.dll"
  211.         --except for close,closetask, and opentask, functions are as
  212.         --in the db_vista docs (dt_ = d_). The last args are *currenttask,dbn
  213.  
  214.         int dt_close    (pointer)
  215.         int dt_closetask(pointer)
  216.         int dt_connect  (int,pointer,int)
  217.         int dt_crget    (pointer,pointer,int)
  218.         
  219.         --other calls ommitted here
  220.  
  221.         int dt_setro    (int,pointer,int)
  222.     end
  223.  
  224.     --chekmate.dll is the helper dll for the checking account system
  225.     linkdll "chekmate.dll"
  226.         --other calls ommitted here
  227.         word dbv_EditRegister (word,int,long,int,word,int)
  228.         word dbv_GetRegister (word,int,word)
  229.     end
  230.  
  231. end
  232.  
  233. [LISTING THREE] 
  234.  
  235. to handle InitGlobals
  236.     system svhControl,  svPtrControl
  237.     system svhDBBuffer, svPtrDBBuffer
  238.     system svhCurrTask, svPtrCurrTask
  239.     set svhControl to  GlobalAlloc (66,64) --GHND is 66, size is 64 bytes
  240.     set svhDBBuffer to GlobalAlloc (66,256)
  241.     set svhCurrTask to GlobalAlloc (66,64)
  242.     if svhControl <= 0 or svhDBBuffer <= 0 or svhCurrTask <= 0
  243.         --clean up, since allocation failed
  244.         send FreeGlobals
  245.         send Exit  -- shutdown the system
  246.     else
  247.         --get pointers
  248.         set svPtrControl  to GlobalLock (svhControl)
  249.         set svPtrDBBuffer to GlobalLock (svhDBBuffer)
  250.         set svPtrCurrTask to GlobalLock (svhCurrTask)
  251.     end
  252. end
  253. to handle FreeGlobals
  254.     system svhControl,  svPtrControl
  255.     system svhDBBuffer, svPtrDBBuffer
  256.     system svhCurrTask, svPtrCurrTask
  257.     if svhControl is not null and svhControl > 0
  258.         get GlobalUnlock (svhControl)
  259.         get GlobalFree   (svhControl)
  260.     end
  261.     if svhDBBuffer is not null and svhDBBuffer > 0
  262.         get GlobalUnlock (svhDBBuffer)
  263.         get GlobalFree   (svhDBBuffer)
  264.     end
  265.     if svhCurrTask is not null and svhCurrTask > 0
  266.         get GlobalUnlock (svhCurrTask)
  267.         get GlobalFree   (svhCurrTask)
  268.     end
  269.     --clean up globals to make ToolBook suspend rather than GP Fault
  270.     set svhControl      to null
  271.     set svhDBBuffer     to null
  272.     set svhCurrTask     to null
  273.     set svPtrControl    to null
  274.     set svPtrDBBuffer   to null
  275.     set svPtrCurrTAsk   to null
  276. end
  277.  
  278. [LISTING FOUR]
  279.  
  280. typedef struct Control {
  281.    HANDLE  hCurrentTask;        //current task structure (DB_TASK)
  282.    HANDLE  hDataBaseBuffer;     //db_Vista's control buffer
  283.  
  284.    // Offscreen image / database address pairs 
  285.    HANDLE  hRegisterImage;      //offscreen image of the register field
  286.    HANDLE  hRegisterDBAArray;   //array of database addresses, 1 for each line
  287.                                 //in the register image
  288.    // Selector fields storage
  289.    HANDLE  hPayeeCodeArray;     //offscreen image of the payee selector field
  290.    HANDLE  hPayeeCodeDBAArray;  //array of database addresses - payee selector
  291.    HANDLE  hPayeeNameArray;     //offscreen image of the payee selector field
  292.    HANDLE  hPayeeNameDBAArray;  //array of database addresses - payee selector
  293.    HANDLE  hAccountCodeArray;   //offscreen image of account selector field
  294.    HANDLE  hAccountCodeDBAArray;//array of database addresses - accts. selector
  295.    HANDLE  hAccountNameArray;   //offscreen image of account selector field
  296.    HANDLE  hAccountNameDBAArray;//array of database addresses - accts selector
  297.    HANDLE  hRegisterNumbers;    //array of deposit, payments, balances 
  298.    
  299.    // Database addresses for active records
  300.    DB_ADDR   dbaCurrPayor;     //address of the current payor record
  301.    DB_ADDR   dbaCurrRegister;  //address of the current active register record
  302.    DB_ADDR   dbaCurrRegisterActual; //address of current month's register 
  303.  
  304.    // Database number for concurrency operations
  305.    int   nDatabaseNumber;     //normally 0
  306.    } CONTROL;
  307.  
  308. [LISTING FIVE]
  309.  
  310. --------------------------
  311. --CONTROL BLOCK ACCESSOR--
  312. --------------------------
  313. to get hControl fField
  314.     system svPtrControl
  315.     set vOffset to ControlOffset(fField)
  316.     set retval to -1
  317.     conditions
  318.     when char 1 of fField is "h" --handles
  319.         set retval to pointerWord(vOffset,svPtrControl)
  320.     when chars 1 to 3 of fField is "dba" --db_addrs
  321.         set retval to pointerlong(vOffset,svPtrControl)
  322.     when char 1 of fField is "n" 
  323.         set retval to pointerint(vOffset,svPtrControl)
  324.     end
  325.     return retval
  326. end
  327.  
  328. to set hControl fField to fVal
  329.     system svPtrControl
  330.     set vOffset to ControlOffset(fField)
  331.     conditions
  332.     when char 1 of fField is "h" --handles
  333.         get pointerWord(vOffset,svPtrControl,fVal)
  334.     when chars 1 to 3 of fField is "dba" --db_addrs
  335.         get pointerlong(vOffset,svPtrControl,fVal)
  336.     when char 1 of fField is "n" 
  337.         get pointerint(vOffset,svPtrControl,fVal)
  338.     end
  339. end
  340.  
  341. to get ControlOffset fField
  342.     conditions
  343.     when char 1 of fField is "h" --handles
  344.         conditions
  345.         when fField is hCurrentTask
  346.             set vOffset to 0
  347.         when fField is hDatabaseBuffer
  348.             set vOffset to 1
  349.         when fField is hRegisterImage
  350.             set vOffset to 2
  351.         when fField is hRegisterDBAArray
  352.             set vOffset to 3
  353.         when fField is hRegisterCodeArray
  354.             set vOffset to 4
  355.         when fField is hRegisterCodeDBAArray
  356.             set vOffset to 5
  357.         when fField is hRegisterNameArray
  358.             set vOffset to 6
  359.         when fField is hRegisterNameDBAArray
  360.             set vOffset to 7
  361.         when fField is hPayeeCodeArray
  362.             set vOffset to 8
  363.         when fField is hPayeeCodeDBAArray
  364.             set vOffset to 9
  365.         when fField is hPayeeNameArray
  366.             set vOffset to 10
  367.         when fField is hPayeeNameDBAArray
  368.             set vOffset to 11
  369.         when fField is hAccountCodeArray
  370.             set vOffset to 12
  371.         when fField is hAccountCodeDBAArray
  372.             set vOffset to 13
  373.         when fField is hAccountNameArray
  374.             set vOffset to 14
  375.         when fField is hAccountNameDBAArray
  376.             set vOffset to 15
  377.         when fField is hRegisterNumbers
  378.             set vOffset to 16
  379.         end
  380.         return vOffset*2
  381.     when chars 1 to 3 of fField is "dba" --db_addrs
  382.         set vbase to 34 -- max(vOffset*2)+2
  383.         conditions
  384.         when fField is dbaCurrPayor
  385.             set vOffset to 0
  386.         when fField is dbaCurrRegister
  387.             set vOffset to 1
  388.         when fField is dbaCurrRegisterActual
  389.             set vOffset to 2
  390.         end
  391.         return vbase+vOffset*4
  392.     when char 1 of fField is "n" 
  393.         set vbase to 46 --vbase + dbaentries * 4
  394.         conditions
  395.         when fField is "nDatabaseNumber"
  396.             set vOffset to 0
  397.         end
  398.         return vbase+vOffset*2
  399.     end
  400. end
  401.  
  402.  
  403. [LISTING SIX]
  404.  
  405. -- Fill selector loads selector text from global memory into selector field 
  406.  
  407. to handle FILLSELECTOR fComboName,fObjectName 
  408.     set vCurdba to dbv_currentrecord() 
  409.     set vHText to hControl("h" & fComboName & "Array") 
  410.     if vhText = 0 
  411.         get createSelectorList (fComboName) 
  412.         set vHText to hControl("h" & fComboName & "Array") 
  413.     end 
  414.     get globalLock (vHText) 
  415.     if fObjectName is null 
  416.         set fObjectName to fComboName 
  417.     end 
  418.     set text of (pListID of group fObjectName) to\ 
  419.         pointerString(0, it) 
  420.     get globalUnLock (vHText) 
  421.     set dbv_currentrecord() to vCurdba 
  422. end 
  423. -- createSelectorList loads global memory block with values from appropriate 
  424. -- set member fields 
  425. to get createSelectorList fArray 
  426.     system svPtrDbBuffer, svPtrCurrTask 
  427.      -- first determine what all the database constants are 
  428.     conditions 
  429.     when fArray is "RegisterName" 
  430.         get dt_findfm(20000,svPtrCurrTask,0) 
  431.         set vSet to 20006 
  432.         get dt_setom(vSet,20000,svPtrCurrTask,0) 
  433.         set vField to 1000 
  434.     -- cases for "RegisterCode", "PayeeCode", "PayeeName", "AccountCode",
  435.     -- and "AccountName" are similar
  436.     else 
  437.         return false 
  438.     end 
  439.     set vArray to "h" & fArray 
  440.      --check if the memory is already allocated
  441.     if hControl(vArray & "Array") = 0 
  442.         set vhTextBuffer to globalAlloc(66,1000) 
  443.         set vhDBABuffer to globalAlloc(66,500) 
  444.         set hControl(vArray & "Array") to vhTextBuffer 
  445.         set hControl(vArray & "DBAArray") to vhDBABuffer 
  446.     else 
  447.         set vhTextBuffer to hControl(vArray & "Array") 
  448.         set vhDBABuffer to hControl(vArray & "DBAArray") 
  449.     end 
  450.     
  451.     set vPtrTextBuffer to globalLock(vhTextBuffer) 
  452.     set vPtrDBABuffer to globalLock(vhDBABuffer) 
  453.     set vDBAOffset to 0 
  454.     set vcharCount to 0 
  455.     get dt_findfm(vSet,svPtrCurrTask,0) 
  456.     while it = 0 
  457.      --build the text buffer 
  458.         get dt_crread(vField,svPtrDbBuffer,svPtrCurrTask,0) 
  459.         set vline to pointerstring(0,svPtrDbBuffer) 
  460.         put CRLF after vLine 
  461.         get pointerstring(vCharCount,vPtrTextBuffer,vLine) 
  462.         increment vCharCount by charcount(vLine) 
  463.       --build the db_addr buffer 
  464.         get dt_crget(svPtrDbBuffer,svPtrCurrTask,0) 
  465.         get pointerlong(0,svPtrDbBuffer) 
  466.         get pointerlong(vDBAOffset,vPtrDBABuffer,it) 
  467.         increment vDBAOffset by 4 -- because DBAs are longs 
  468.       --get next record 
  469.         get dt_findnm(vSet,svPtrCurrTask,0)     
  470.     end    
  471.     return true     
  472.     get globalunLock(vhTextBuffer) 
  473.     get globalunLock(vhDBABuffer) 
  474. end 
  475.  
  476. [LISTING SEVEN] 
  477.  
  478. /*****************************************************************************
  479.  * dbv_CreateSelectorList--Purpose: Obtains list of available selections for
  480.  *  a particular chekmate field and save them along with database addresses 
  481.  *  in the chekmate control block.
  482.  * Parameters: hControl, HANDLE to the database control block; nSetID, numeric
  483.  *  identifier for set containing selection list; lField, LONG database field 
  484.  *  number; nHandleOffset, integer offset into the Control block of handle for
  485.  *  memory where data should be stored.
  486.  * Return Value: 0, if no errors; -n, if errors reading database
  487.  */
  488. extern WORD FAR PASCAL dbv_CreateSelectorList(
  489.       HANDLE   hControl,         // Control Block
  490.       int      nSetID,           // database set identifier
  491.       LONG     lField,           // database field number
  492.       int      hHandleOffset)    // offset in Control Block for memory handle
  493. {
  494.    int      i;
  495.    int             iError=-1;       // error return code
  496.    LPCONTROL       lpControl=NULL;  // control block
  497.    DB_TASK DB_FAR *lpTask=NULL;     // task pointer
  498.    LPHANDLE        lpHandle;        // handle pointer
  499.    if (NULL==hControl)
  500.    {
  501.       return -1;  // control block not initialized
  502.    }
  503.  
  504.    // Lock control block so task block can be locked for database call.
  505.    lpControl  = (LPCONTROL) GlobalLock (hControl);
  506.    lpTask     = (DB_TASK DB_FAR *) GlobalLock (lpControl->hCurrentTask);
  507.  
  508.    // point to handle in control block for list text. 
  509.    lpHandle   = ((LPHANDLE) lpControl) + hHandleOffset; 
  510.    iError = LoadSelectorList (lpHandle,lpHandle+1,nSetID,lField,lpTask,
  511.                                                    lpControl->nDatabaseNumber);
  512. CleanUp:
  513.    GlobalUnlock (lpControl->hCurrentTask);
  514.    GlobalUnlock (hControl);
  515.    return (iError);
  516. }
  517.  
  518. /******************************************************************************
  519.  * LoadSelectorList--Purpose: Reads database for specified set and transfer
  520.  *   data from lField into text buffer. Each record a separate text line in 
  521.  *   buffer and database addresses for each record will also be saved.
  522.  * Parameters: lphListText, handle to memory for list text; lphListDBA, handle 
  523.  *   to memory for list database addresses; nSetID, numeric identifier for 
  524.  *   database set containing the selection list; lField, LONG database field 
  525.  *   number; lpTask, pointer to database task; nDatabase, database number
  526.  * Return Value: 0, if no errors; -n,  if errors reading database
  527.  */
  528. int PASCAL LoadSelectorList (
  529.          LPHANDLE    lphListText,      // handle to memory for list text
  530.          LPHANDLE    lphListDBA,       // memory handle for list database adr.
  531.          int         nSetID,           // database set ID
  532.          LONG        lField,           // database field number for list text
  533.          DB_TASK DB_FAR *lpTask,       // database task
  534.          int         nDatabase)        // database number
  535. {
  536.    int          iError=-1;    // error return code
  537.    int          nDBA=0;       // number of DBA's
  538.    int          nMaxDBA=0;    // maximum number of DBA's used
  539.    int          nMaxBytes=0;  // maximum bytes allowed
  540.    LPSTR        lpText=NULL;  // current text line
  541.    DB_ADDR FAR *lpDBA=NULL;   // database address value
  542.    HANDLE       hMem;         // handle to reallocated memory block
  543.    DB_ADDR      lCurDBA;      // current database record
  544.  
  545.    // save the current database record
  546.    dt_crget ((DB_ADDR FAR *)&lCurDBA,lpTask,nDatabase);
  547.  
  548.    // initialize the text and DBA memory blocks.  
  549.    if (*lphListText == NULL)
  550.    {
  551.       *lphListText = GlobalAlloc (DLL_ALLOC,SELECTOR_TEXT_SIZE);
  552.    }
  553.    if (*lphListDBA == NULL)
  554.    {
  555.       *lphListDBA = GlobalAlloc (DLL_ALLOC,(LONG)(SELECTOR_DBA_COUNT*sizeof
  556.                                                                   (DB_ADDR)));
  557.    }
  558.    if (*lphListText == NULL || *lphListDBA == NULL)
  559.    {
  560.       goto CleanUp;
  561.    }
  562.  
  563.    // initial allocations to set the maximum values and lock the memory blocks.
  564.    nMaxDBA   = GlobalSize (*lphListDBA) / sizeof(DB_ADDR);
  565.    nMaxBytes = GlobalSize (*lphListText);
  566.    
  567.    lpText = GlobalLock (*lphListText);
  568.    lpDBA  = (DB_ADDR FAR *) GlobalLock (*lphListDBA);
  569.  
  570.    // read the database and fill in the text values
  571.    for (iError = dt_findfm (nSetID,lpTask,nDatabase);
  572.         iError==S_OKAY;
  573.         iError = dt_findnm (nSetID,lpTask,nDatabase))
  574.    {
  575.       if (nMaxBytes<=MIN_SELECTOR_TEXT_SIZE)
  576.       {
  577.          // need to allocate more text memory.  
  578.          lpText = NULL;
  579.          GlobalUnlock (*lphListText);
  580.          hMem = GlobalReAlloc (*lphListText,
  581.                                GlobalSize(*lphListText)+SELECTOR_TEXT_SIZE,
  582.                                GMEM_ZEROINIT);
  583.          if (hMem==NULL)
  584.          {
  585.             iError = -2;
  586.             goto CleanUp;  // not enough memory
  587.          }
  588.          *lphListText = hMem;  // new handle
  589.          lpText       = GlobalLock (*lphListText);
  590.          nMaxBytes    = GlobalSize(*lphListText) - lstrlen (lpText);
  591.          lpText      += lstrlen(lpText);
  592.       }
  593.       // read the field contents into the text buffer
  594.       dt_crread(lField,lpText,lpTask,nDatabase);
  595.       lstrcat (lpText,"\r\n");
  596.       lpText += lstrlen(lpText);
  597.  
  598.       // save the DBA of the record
  599.       if (nDBA >= nMaxDBA)
  600.       {
  601.          // need to allocate more DBA memory.  
  602.          lpDBA = NULL;
  603.          GlobalUnlock (*lphListDBA);
  604.          hMem = GlobalReAlloc (*lphListDBA,
  605.                     GlobalSize(*lphListDBA)+SELECTOR_DBA_COUNT*sizeof(DB_ADDR),
  606.                                                                GMEM_ZEROINIT);
  607.          if (hMem==NULL)
  608.          {
  609.             iError = -2;
  610.             goto CleanUp;  // not enough memory
  611.          }
  612.          *lphListDBA = hMem;  // new handle
  613.          lpDBA       = (DB_ADDR DB_FAR *)GlobalLock (*lphListDBA);
  614.          nMaxDBA     = GlobalSize(*lphListDBA) - nDBA;
  615.          lpDBA      += nDBA;
  616.       }
  617.       dt_crget   (lpDBA,lpTask,nDatabase);
  618.       lpDBA++;
  619.       nDBA++;
  620.    }
  621. CleanUp:
  622.    // restore the address of the current record
  623.    dt_crset ((DB_ADDR far *)&lCurDBA,lpTask,nDatabase);
  624.    if (lpText!=NULL)
  625.    {
  626.       GlobalUnlock (*lphListText);
  627.    }
  628.    if (lpDBA!=NULL)
  629.    {
  630.       GlobalUnlock (*lphListDBA);
  631.    }
  632.    if (iError==S_EOS) 
  633.    {
  634.       iError = S_OKAY;
  635.    }
  636.    return (iError);
  637. }
  638.  
  639.  
  640.  
  641. [BALANCE MAINTENACE CODE]
  642.  
  643. typedef struct RegisterNumbers {
  644.    long  lDeposit;   //value of the deposit (may be 0)
  645.    long  lPayment;   //value of the payment (may be 0)
  646.    long  lBalance;   //value of the balance
  647.    } REGISTERNUMBERS;
  648.  
  649. /*******************************************************************************
  650.  * UpdateRegisterNumbers
  651.  *
  652.  *     Purpose: 
  653.  *    This routine will update the register payments, deposits and balance
  654.  *    arrays.  Additonally it will copy the information into the register
  655.  *    text arrays and add the final zero byte to the register text
  656.  *
  657.  *     Parameters:
  658.  *       lpControl      pointer to the control block
  659.  *    
  660.  *     Return Value:
  661.  *       0  if no errors
  662.  *       
  663.  */
  664. int PASCAL UpdateRegisterNumbers(
  665.          LPCONTROL   lpControl)  // pointer to the Control block
  666. {
  667.    int i;
  668.    char cPayment[20], cDeposit[20], cBalance[20];
  669.    LONG              lBegBal;       // begining balance
  670.    LPREGISTERNUMBERS lpNumbers;     // register numbers
  671.    LPREGISTERIMAGE   lpImage;       // register image block
  672.    LPSTR             lpLine;        // register line image
  673.    LONG              lPrevBal;      // previous balance
  674.    
  675.    lpImage      = (LPREGISTERIMAGE)   GlobalLock (lpControl->hRegisterImage);
  676.    lpNumbers    = (LPREGISTERNUMBERS) GlobalLock (lpControl->hRegisterNumbers);
  677.    lpLine       = (LPSTR) &(lpImage->Text[0]);
  678.  
  679.    // we first go thru the list of numbers and set the balances and then
  680.    // we convert the values to strings and place them into the register
  681.    //  line.  Note the register lines are assumed to be blank filled and
  682.    //  terminated with a CRLF.
  683.  
  684.    for (i=0,lPrevBal=lpNumbers->lBalance;i<lpImage->nLines;i++,lpNumbers++)
  685.    {
  686.       lPrevBal  =
  687.           lpNumbers->lBalance = lPrevBal + 
  688.                             lpNumbers->lDeposit - lpNumbers->lPayment;
  689.  
  690.       // convert the values to zero terminated strings
  691.       Long2Money (lpNumbers->lPayment,(LPSTR) &(cPayment[0]));
  692.       Long2Money (lpNumbers->lDeposit,(LPSTR) &(cDeposit[0]));
  693.       Long2Money (lpNumbers->lBalance,(LPSTR) &(cBalance[0]));
  694.       wsprintf (lpLine+50," %10s   %10s %10s",
  695.                 (LPSTR) &(cPayment[0]),
  696.                 (LPSTR) &(cDeposit[0]),
  697.                 (LPSTR) &(cBalance[0]));
  698.  
  699.       // now add the CRLF to the lines the current zero byte placed in
  700.       // the lpLine will be overwritten and no zero byte will be used.
  701.       lpLine += lstrlen(lpLine);  // positioned at the zero byte
  702.       *lpLine++ = '\r';
  703.       *lpLine++ = '\n';
  704.       // lpLine now positioned correctly for begining of next line
  705.    }
  706.    // add the final empyt line and a zero byte to terminate the register text field
  707.    lstrcat (lpLine,"\r\n");
  708.  
  709.    GlobalUnlock (lpControl->hRegisterImage);
  710.    GlobalUnlock (lpControl->hRegisterNumbers);
  711.    return (0);
  712. }
  713.  
  714.  
  715. /*******************************************************************************
  716.  * Long2Money
  717.  *
  718.  *     Purpose: 
  719.  *    convert a long number into a money text string. The numeric value
  720.  *    is in terms of cents.
  721.  *
  722.  *     Parameters:
  723.  *       lValue   LONG value to be converted
  724.  *       lpText   LPSTR to the text string
  725.  *    
  726.  *     Return Value:
  727.  *       LPSTR    pointer to the text string
  728.  *       
  729.  */
  730. LPSTR PASCAL Long2Money(
  731.    LONG  lValue,           // long value to be converted
  732.    LPSTR lpDecimalText)    // 
  733. {
  734.    LPSTR lpStr = lpDecimalText;
  735.  
  736.    // Take care of the sign of the number so that the conversion
  737.    // will only have to deal with positive values.
  738.    if (lValue <0)
  739.    {
  740.       lValue = -lValue;
  741.       *lpStr++ = '-';  
  742.    }
  743.    // convert the number to characters - note if the value is less
  744.    // than 100 then we will want the number to be be converted as
  745.    // 0.nn  Therefore 100 will be added to the value and then later
  746.    // the '1' will be replaced with a '0'.
  747.  
  748.    wsprintf (lpStr,"%li",(LONG) ((lValue<100)?lValue+100:lValue));
  749.  
  750.    // now make room for the decimal point
  751.    lpStr += lstrlen(lpStr);       // lpStr points to the end of the string
  752.    *(lpStr+1) = *lpStr; lpStr--;  // terminating character
  753.    *(lpStr+1) = *lpStr; lpStr--;  // units digit
  754.    *(lpStr+1) = *lpStr;           // tens digit   
  755.    *lpStr--   = '.';              // add in the decimal point
  756.    if (lValue < 100)
  757.    {
  758.       *lpStr = '0';  // replace the '1' with a '0' forces leading zero
  759.    }
  760.    return (lpDecimalText);
  761. }
  762.  
  763. [REGISTER MAINTENANCE CODE]
  764.  
  765. /*******************************************************************************
  766.  * dbv_GetRegister
  767.  *
  768.  *     Purpose: 
  769.  *    This routine will read the transactions associated with the current
  770.  *    account for a given month and generates a checkbook register image.
  771.  *    The image is saved in memory and also set into the toolbook fields
  772.  *    specified in hFldTable.
  773.  *
  774.  *     Parameters:
  775.  *       hControl          HANDLE to the database control block
  776.  *       nSetID            numeric identifier for database set
  777.  *       hFldTable         HANDLE to the ToolBook field table list
  778.  *    
  779.  *     Return Value:
  780.  *       0  if no errors
  781.  *       1  if error in setting field
  782.  *      -1  control block not initialized
  783.  *       
  784.  */
  785. extern WORD FAR PASCAL dbv_GetRegister(
  786.       HANDLE   hControl,         // Control Block
  787.       int      nSetID)           // database set identifier
  788. {
  789.    int i;
  790.    int             iError=0;        // error return
  791.    LPCONTROL       lpControl=NULL;  // control block
  792.    int             nDatabase;       // database number
  793.    LPREGISTERIMAGE lpImage=NULL;    // pointer to the register image block
  794.  
  795.    // Lock the control block so that the task block and the database
  796.    // buffer can be obtained.  The database buffer will be used to contain
  797.    // the individual field values for the current record.
  798.  
  799.    if (NULL==hControl)
  800.    {
  801.       return -1;  // control block not initialized
  802.    }
  803.  
  804.    // Lock the control block so that the task block can be locked for the
  805.    // database call.  Then lock the field table so that we can access
  806.    // which ToolBook fields are to be set.
  807.  
  808.    lpControl  = (LPCONTROL) GlobalLock (hControl);
  809.    lpFldTable = (LPFLDTABLE) GlobalLock(hFldTable);
  810.  
  811.    // Initialize the memory blocks that will be used for the register
  812.    // information.
  813.    if (0!=(iError=InitRegisterImage(lpControl)))
  814.    {
  815.       goto CleanUp;
  816.    }
  817.  
  818.    // Now we load the register image
  819.    if (0!=(iError=LoadRegisterImage (lpControl,nSetID)))
  820.    {
  821.       goto CleanUp;
  822.    }
  823.  
  824.    GlobalUnlock (lpControl->hRegisterImage);
  825.   
  826.          
  827. CleanUp:
  828.  
  829.    // all done - now unlock all the allocations
  830.    GlobalUnlock (lpFldTable->hBookName);
  831.    GlobalUnlock (hFldTable);
  832.    GlobalUnlock (hControl);
  833.    return 0;
  834. }
  835.  
  836. /*******************************************************************************
  837.  * InitRegisterImage
  838.  *
  839.  *     Purpose: 
  840.  *    This routine will initialize the memory blocks that will contain the
  841.  *    chekmate register image, the database addresses and the array of the
  842.  *    deposits, payments and balances for the register.
  843.  *
  844.  *     Parameters:
  845.  *       lpControl      pointer to the control block
  846.  *    
  847.  *     Return Value:
  848.  *       0  if no errors
  849.  *      -1  if error allocating the memory
  850.  *       
  851.  */
  852. int PASCAL InitRegisterImage(
  853.          LPCONTROL   lpControl)  // pointer to the Control block
  854. {
  855.    LPREGISTERIMAGE lpImage;      // pointer to the register image
  856.  
  857.    // if the handles are currently pointing to memory blocks then we free
  858.    // them and re-allocate. This is done just to make life a little easier
  859.  
  860.    if (NULL!=lpControl->hRegisterImage)
  861.    {
  862.       GlobalFree (lpControl->hRegisterImage);
  863.       lpControl->hRegisterImage = NULL;
  864.    }
  865.    if (NULL!=lpControl->hRegisterDBAArray)
  866.    {
  867.       GlobalFree (lpControl->hRegisterDBAArray);
  868.       lpControl->hRegisterDBAArray = NULL;
  869.    }
  870.    if (NULL!=lpControl->hRegisterNumbers)
  871.    {
  872.       GlobalFree (lpControl->hRegisterNumbers);
  873.       lpControl->hRegisterNumbers = NULL;
  874.    }
  875.   
  876.    // now allocate the space for the register image array
  877.    lpControl->hRegisterImage = GlobalAlloc (DLL_ALLOC,
  878.                                    (LONG) sizeof(REGISTERIMAGE)+
  879.                                    (INITIALREGISTERLINES*REGISTERLINESIZE));
  880.    if (NULL==lpControl->hRegisterImage)
  881.    {
  882.       return -1;
  883.    }
  884.    // now allocate the database address lists
  885.    lpControl->hRegisterDBAArray = GlobalAlloc (DLL_ALLOC,
  886.                                       ((long) sizeof(DB_ADDR))*((long) INITIALREGISTERLINES));
  887.    if (NULL==lpControl->hRegisterDBAArray)
  888.    {
  889.       return -1;
  890.    }
  891.  
  892.    // now allocate the register payments, deposits and balance columns
  893.    lpControl->hRegisterNumbers = GlobalAlloc (DLL_ALLOC,
  894.                                       ((long) sizeof(REGISTERNUMBERS))*((long) 
  895. INITIALREGISTERLINES));
  896.    if (NULL==lpControl->hRegisterNumbers)
  897.    {
  898.       return -1;
  899.    }
  900.  
  901.    // initialize the image structure to contain the header information
  902.    lpImage = (LPREGISTERIMAGE) GlobalLock (lpControl->hRegisterImage);
  903.    lpImage->nMaxLines = INITIALREGISTERLINES;
  904.    lpImage->nLines    = 0;
  905.  
  906.    GlobalUnlock (lpControl->hRegisterImage);   
  907.    return (0);
  908. }
  909.  
  910.  
  911.  
  912. /*******************************************************************************
  913.  * LoadRegisterImage
  914.  *
  915.  *     Purpose: 
  916.  *    This routine will load the register data from the database.
  917.  *
  918.  *     Parameters:
  919.  *       lpControl      pointer to the control block
  920.  *       nSetID         transaction set id
  921.  *    
  922.  *     Return Value:
  923.  *       0  if no errors
  924.  *      -1  if error reading the database
  925.  *       
  926.  */
  927. int PASCAL LoadRegisterImage(
  928.          LPCONTROL   lpControl,  // pointer to the Control block
  929.          int         nSetID)     // set containing the transaction members
  930. {
  931.    int i;
  932.    int               iError=0;      // error return
  933.    DB_ADDR           lCurDBA;       // current database address
  934.    actual            Actual;        // current months value
  935.    payee             Payee;         // current transactions payee
  936.    transaction       Transaction;   // current transaction
  937.    int               nDatabase;     // database number
  938.    DB_ADDR           lTranDBA;      // transaction dba
  939.    DB_TASK DB_FAR   *lpTask=NULL;   // task pointer
  940.    DB_ADDR FAR      *lpDBA;         // database address array
  941.    LPREGISTERNUMBERS lpNumbers;     // register numbers
  942.    LPREGISTERIMAGE   lpImage;       // register image block
  943.    LPSTR             lpLine;        // line for the register image
  944.  
  945.    // lock the task, the register image, the database addresses array
  946.    // and the register number array.
  947.  
  948.    lpTask    = (DB_TASK DB_FAR *)  GlobalLock (lpControl->hCurrentTask);
  949.    nDatabase = lpControl->nDatabaseNumber;
  950.  
  951.    // save the current database record
  952.    dt_crget ((DB_ADDR FAR *)&lCurDBA,lpTask,nDatabase);
  953.  
  954.    // now we load up the register data.  The fist line in the register is
  955.    // the begining balance.  We "Fake out" the first line by creating
  956.    // a psudeo transaction record for the actual month record.
  957.  
  958.    dt_crset ((DB_ADDR far *)&(lpControl->dbaCurrRegisterActual),lpTask,nDatabase);
  959.    dt_setor (nSetID,lpTask,nDatabase);
  960.    if (S_OKAY!=(iError=dt_recread((DB_ADDR FAR *)&Actual,lpTask,nDatabase)))
  961.    {
  962.       goto CleanUp;
  963.    }
  964.    lpImage   = (LPREGISTERIMAGE)   GlobalLock (lpControl->hRegisterImage);
  965.    lpDBA     = (DB_ADDR FAR *)     GlobalLock (lpControl->hRegisterDBAArray);
  966.    lpNumbers = (LPREGISTERNUMBERS) GlobalLock (lpControl->hRegisterNumbers);
  967.  
  968.    Transaction.cTranType   = BBAL;     // begining balance
  969.    Transaction.lTranDate   = 19000001 + (Actual.nActualMonth)*100; // date
  970.    Transaction.nTranNumber = 0;        // transaction number
  971.    Transaction.bTranClear  = 0;
  972.    Transaction.lTranAmount = Actual.lActualAmount;
  973.    lpNumbers->lBalance     = Actual.lActualAmount;
  974.    dt_crget (lpDBA++,lpTask,nDatabase);
  975.    GenerateRegisterLine ((LPTRANSACTION) &Transaction,(LPPAYEE) &Payee,&(lpImage->Text[0]));
  976.    lpImage->nLines++;
  977.    lpNumbers++;   
  978.  
  979.    GlobalUnlock (lpControl->hRegisterImage);
  980.    GlobalUnlock (lpControl->hRegisterDBAArray);
  981.    GlobalUnlock (lpControl->hRegisterNumbers);
  982.  
  983.    // now step thru the database reading the members of the set and
  984.    // generating register lines for them.
  985.    for (iError=dt_findfm (nSetID,lpTask,nDatabase),i=1;
  986.         iError==S_OKAY;
  987.         iError=dt_findnm (nSetID,lpTask,nDatabase),i++)
  988.    {
  989.       dt_crget   ((DB_ADDR FAR *) &lTranDBA,lpTask,nDatabase);
  990.       EditRegisterImage (lpControl,i,lTranDBA,nSetID,ADD_TRAN);
  991.    }
  992.  
  993.    // now fill in the payment, deposit and balance fields
  994.    UpdateRegisterNumbers (lpControl);
  995.  
  996.  CleanUp:
  997.    // restore the address of the current record
  998.    dt_crset ((DB_ADDR far *)&lCurDBA,lpTask,nDatabase);
  999.  
  1000.    GlobalUnlock (lpControl->hCurrentTask);
  1001.  
  1002.    return (((iError==S_EOS)?S_OKAY:iError));
  1003.   
  1004. }
  1005.  
  1006.  
  1007. [DB_VISTA SHELL CODE]
  1008.  
  1009. -- composite functions for adding and editing records
  1010.  
  1011. to get dbv_AddRecord fHDbControl, ftbFields, fRecordID
  1012.     system svPtrCurrTask,svPtrDbBuffer
  1013.  
  1014.     get dt_fillnew(fRecordID,svPtrDbBuffer,svPtrCurrTask,0)
  1015.     get last char of fRecordID
  1016.     set vStartingField to it *1000 --starting fields of VISTA records are on 1000 boundries
  1017.     return dbv_EditRecord(fHDbControl, fTbFields, vStartingField)
  1018. end     
  1019.  
  1020.  
  1021. to get dbv_EditRecord fHDbControl, ftbFields, fStartingField
  1022.     system svPtrCurrTask,svPtrDbBuffer
  1023.     set vFldCount to itemcount( fTbFields )
  1024.     step i from 1 to vFldCount
  1025.         get item i of fTbFields
  1026.         get pointerstring(0,svPtrDbBuffer,text of field id it)
  1027.         get dt_crwrite(fStartingField+i,svPtrDbBuffer,svPtrCurrTask,0)
  1028.     end
  1029.     return true
  1030. end
  1031.  
  1032.  
  1033. to get dbv_GetTBFieldArray fhDBControl, fSet, fFieldID, fTbFields
  1034.     system svPtrDbBuffer,svPtrCurrTask, svCurrAccountDBA
  1035.  
  1036.     set vCurDBA to dbv_currentrecord()
  1037.     get dt_findfm(fSet,svPtrCurrTask,0)
  1038.     if it = 0
  1039.         set vFldCount to itemcount( fTbFields)
  1040.         step i from 1 to vFldCount
  1041.             get dt_crread(fFieldID,svPtrDbBuffer,svPtrCurrTask,0)
  1042.             set vID to item i of fTbFields
  1043.             set text of field id vID\
  1044.                 to pointerLong(0,svPtrDbBuffer)/10
  1045.             format text of field id vID as "0.00"
  1046.             if dt_findnm(fSet,svPtrCurrTask,0) <> 0
  1047.                 break step
  1048.             end
  1049.         end
  1050.     end
  1051.     set dbv_currentrecord() to vCurDBA
  1052.     return true
  1053. end
  1054.  
  1055. to get dbv_EditTBFieldArray fhDBControl, fhFldTable, fSet, fTbFields
  1056.     system ,svPtrDbBuffer,svPtrCurrTask, svCurrAccountDBA
  1057.  
  1058.     set vCurDBA to dbv_currentrecord()
  1059.     get dt_findfm(fSet,svPtrCurrTask,0)
  1060.         if it = 0
  1061.         set vFldCount to itemcount( fTbFields )
  1062.         step i from 1 to vFldCount
  1063.             get text of field id (item i of fTbFields)
  1064.             format it as "0"
  1065.             get pointerLong(0,svPtrDbBuffer,it)
  1066.             get dt_crwrite(fFieldID,svPtrDbBuffer,svPtrCurrTask,0)
  1067.             if dt_findnm(fSet,svPtrCurrTask,0) <> 0
  1068.                 break step
  1069.             end
  1070.         end
  1071.     end
  1072.     set dbv_currentrecord() to vCurDBA
  1073.     return true
  1074. end
  1075.  
  1076. to get dbv_field fType,fFieldNumber
  1077.     system svhControl,svPtrCurrTask,svPtrDbBuffer
  1078.     get dt_crread(fFieldNumber,svPtrDbBuffer,svPtrCurrTask,0)
  1079.     if fType is "CHAR"
  1080.         set vVal to pointerByte(0,svPtrDbBuffer)
  1081.         set vVal to ansitochar(vVal)
  1082.     else
  1083.         execute "set vVal to pointer" & fType & "(0,svPtrDbBuffer)"
  1084.     end
  1085.     return vVal
  1086. end
  1087.  
  1088. to set dbv_field  fType,fFieldNumber to fVal
  1089.     system svhControl,svPtrCurrTask,svPtrDbBuffer
  1090.     if ftype is "CHAR"
  1091.         get chartoansi(fVal)
  1092.         get pointerbyte (0,svPtrDbBuffer,it)
  1093.     else
  1094.         execute "get pointer" & fType & "(0,svPtrDbBuffer,fVal)"
  1095.     end
  1096.     get dt_crwrite(fFieldNumber,svPtrDbBuffer,svPtrCurrTask,0)
  1097. end
  1098.  
  1099.  
  1100.  
  1101.  
  1102. -- db_vISTA shell functions
  1103.  
  1104. to get dbv_connectSet fSet
  1105.     system svPtrCurrTask
  1106.     get dt_connect(fSet,svPtrCurrTask,0)
  1107. end
  1108.  
  1109. to get dbv_currentOwnerField fSet, fType, fFieldNumber
  1110.     system svhControl,svPtrCurrTask,svPtrDbBuffer
  1111.     get dt_csoread(fSet,fFieldNumber,svPtrDbBuffer,svPtrCurrTask,0)
  1112.     if fType is "CHAR"
  1113.         set vVal to pointerByte(0,svPtrDbBuffer)
  1114.         set vVal to ansitochar(vVal)
  1115.     else
  1116.         execute "set vVal to pointer" & fType & "(0,svPtrDbBuffer)"
  1117.     end
  1118.     return vVal
  1119. end
  1120.  
  1121. to set dbv_currentOwnerField fSet, fType, fFieldNumber to fVal
  1122.     system svhControl,svPtrCurrTask,svPtrDbBuffer
  1123.     if ftype is "CHAR"
  1124.         get chartoansi(fVal)
  1125.         get pointerbyte (0,svPtrDbBuffer,it)
  1126.     else
  1127.         execute "get pointer" & fType & "(0,svPtrDbBuffer,fVal)"
  1128.     end
  1129.     get dt_csowrite(fSet,fFieldNumber,svPtrDbBuffer,svPtrCurrTask,0)
  1130. end
  1131.  
  1132. to get dbv_memberCount fSet 
  1133.     system svPtrCurrTask,svPtrDbBuffer
  1134.     get dt_members(fSet,svPtrDbBuffer,svPtrCurrTask,0)
  1135.     return (pointerLong(0,svPtrDbBuffer))
  1136. end
  1137.  
  1138. to get dbv_findFirstMember fSet
  1139.     system svPtrCurrTask
  1140.     return dt_findfm(fSet,svPtrCurrTask,0)
  1141. end
  1142.  
  1143. to get dbv_setOwnerToCurrRec fSet
  1144.     system svPtrCurrTask
  1145.     return dt_setor(fSet,svPtrCurrTask,0)
  1146. end
  1147.  
  1148.  
  1149. to get dbv_currentOwner fSet
  1150.     system svPtrCurrTask,svPtrDbBuffer
  1151.     set verror to dt_csoget(fSet,svPtrDbBuffer,svPtrCurrTask,0)
  1152.     set vdba to pointerlong(0,svPtrDbBuffer)
  1153.     set sysError to vError
  1154.     return vdba
  1155. end
  1156.  
  1157. to set dbv_currentOwner fSet to fDBA
  1158.     system svPtrCurrTask,svPtrDbBuffer
  1159.     if fDBA is null or fDBA is 0 
  1160.     get dbv_currentOwner(fSet)    
  1161.     if sysError = 0
  1162.             get dt_discon(fSet,svPtrCurrTask,0)
  1163.         end
  1164.     else
  1165.         get pointerlong(0,svPtrDbBuffer,fDBA)
  1166.         get dt_csoset(fSet,svPtrDbBuffer,svPtrCurrTask,0)
  1167.     end
  1168. end
  1169.  
  1170.  
  1171.  
  1172. to set dbv_connectOwner fSet to fDBA
  1173.     system svPtrCurrTask,svPtrDbBuffer
  1174.     set vCurrDBA to dbv_currentRecord()
  1175.     if dt_ismember(fSet,svPtrCurrTask,0) = 0
  1176.             get dt_discon(fSet,svPtrCurrTask,0)
  1177.     end
  1178.     if not(fDBA is null or fDBA is 0 )
  1179.         get pointerlong(0,svPtrDbBuffer,fDBA)
  1180.         get dt_csoset(fSet,svPtrDbBuffer,svPtrCurrTask,0)
  1181.         get dbv_currentmember(fSet)
  1182.         get dbv_currentrecord()
  1183.         get dbv_currentType()
  1184.         get dbv_currentOwner(fset)
  1185.         
  1186.         --get dt_csmset(fSet,)
  1187.         get dt_connect(fSet,svPtrCurrTask,0)
  1188.     end
  1189. end
  1190.  
  1191. to get dbv_currentMember fSet
  1192.     system svPtrCurrTask,svPtrDbBuffer
  1193.     set verror to dt_csmget(fSet,svPtrDbBuffer,svPtrCurrTask,0)
  1194.     set vdba to pointerlong(0,svPtrDbBuffer)
  1195.     set sysError to vError
  1196.     return vdba
  1197. end
  1198.  
  1199. to get dbv_currentType
  1200.     system svPtrCurrTask,svPtrDbBuffer
  1201.     get dt_crtype(svPtrDbBuffer,svPtrCurrTask,0)
  1202.     return pointerint(0,svPtrDbBuffer)
  1203. end
  1204.  
  1205. to get dbv_currentRecord
  1206.     system svPtrCurrTask,svPtrDbBuffer
  1207.     set verror to dt_crget(svPtrDbBuffer,svPtrCurrTask,0)
  1208.     set vdba to pointerlong(0,svPtrDbBuffer)
  1209.     set sysError to vError
  1210.     return vdba
  1211. end
  1212.  
  1213. to set dbv_currentRecord to fDBA
  1214.     system svPtrCurrTask,svPtrDbBuffer
  1215.     get pointerlong(0,svPtrDbBuffer,fDBA)
  1216.     get dt_crset(svPtrDbBuffer,svPtrCurrTask,0)
  1217. end
  1218.  
  1219.  
  1220. --dbv_findKey finds the key that matches fKeyVal, or the next higher key that
  1221. --contains fKeyVal
  1222.  
  1223. to get dbv_findkey  fField, fKeyVal, fType
  1224.     system svPtrDbBuffer,svPtrCurrTask
  1225.     execute ("get pointer" & fType & "(0,svPtrDbBuffer,fKeyVal)")
  1226.     get dt_keyfind(fField, svPtrDbBuffer, svPtrCurrTask,0)
  1227.     if it <> 0
  1228.         get dt_keynext(fField,svPtrCurrTask,0)
  1229.         if it <> 0
  1230.             return -2
  1231.         end
  1232.         execute ("get pointer" & fType & "(0,svPtrDbBuffer)")
  1233.         if fKeyVal is in it
  1234.             return 0
  1235.         else
  1236.             return -1
  1237.         end
  1238.     end
  1239. end
  1240.  
  1241. -- dbv_findrecord navigates through a set to find the nearest member of a set
  1242. -- that matches or exceeds fVal
  1243. to get dbv_findrecord fSet,fField,fVal,fType
  1244.     system svPtrDbBuffer,svPtrCurrTask
  1245.     set vCurrDBA to dbv_currentrecord()
  1246.     set sysError to -1 
  1247.     set retval to 0
  1248.     set dbv_currentowner (fSet) to vCurrDBA
  1249.     get dt_findfm(fSet,svPtrCurrTask,0)
  1250.     if it = 0
  1251.         get dt_crread(fField, svPtrDbBuffer, svPtrCurrTask, 0)
  1252.         execute ("set vdbVal to pointer" & fType &"(0,svPtrDbBuffer)")
  1253.         while vdbval <= fVal as text
  1254.             if vdbval is fval
  1255.                 set retval to dbv_currentrecord()
  1256.                 break while
  1257.             end
  1258.             get dt_findnm(fSet,svPtrCurrTask,0)
  1259.             if it <> 0
  1260.                 break while
  1261.             end
  1262.             get dt_crread(fField, svPtrDbBuffer, svPtrCurrTask, 0)
  1263.             set it to "set vdbVal to pointer" & fType &"(0,svPtrDbBuffer)"
  1264.             execute it
  1265.         end
  1266.     end
  1267.     set dbv_currentrecord() to vCurrDBA
  1268.     return retval
  1269. end
  1270.  
  1271.  
  1272.